﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Net.Mail;
using System.Data.Linq;
using System.ServiceModel.Activation;
using System.Xml.Linq;
using System.Web;
using System.Threading;
using System.Configuration;

namespace GreetingWCFService
{
    // We need ASP.NET compability to be able to handle sessions in WCF.
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class GreetingService : IGreetingService
    {
        #region Fields

        // TODO: Set mail server name in Web.config.
        private string _mailServerName = ConfigurationManager.AppSettings.Get("smtpServer");
        private int _mailServerPort = 25;

        #endregion Fields
        #region IGreetingServiceMembers

        public GreetingResponse SaveAndSendGreeting(string captchaAnswer, GreetingData greetingData, SenderInfo senderInfo)
        {
            GreetingResponse response = ValidateCaptcha(captchaAnswer);
            
            if (response.Status == GreetingStatus.CaptchaFailed)
            {
                return response;
            }

            // Save email.
            string id = SaveGreeting(greetingData);
            response.Message = id;

            // Send email.            
            response.Status = SendGreeting(id, senderInfo);            

            return response;
        }

        public GreetingResponse SaveGreeting(string captchaAnswer, GreetingData greetingData)
        {
            GreetingResponse response = ValidateCaptcha(captchaAnswer);

            if (response.Status == GreetingStatus.CaptchaFailed)
            {                
                return response;
            }

            response.Status = GreetingStatus.Succeeded;
            response.Message = SaveGreeting(greetingData);

            return response;
        }

        public GreetingData GetGreeting(Guid id)
        {
            GreetingData greetingData = null;

            using (LinqToGreetingsDBDataContext dataSource = new LinqToGreetingsDBDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["GreetingsDatabaseConnectionString"].ConnectionString))
            {
                Greeting greeting = (from g in dataSource.Greetings
                                     where g.GreetingID == id
                                     select g).FirstOrDefault<Greeting>();

                greetingData = GreetingToGreetingDataTranslator.GreetingToGreetingData(greeting);
            }

            return greetingData;
        }

        #region Captcha

        private static Captcha captcha = null;
        private static Dictionary<string, XDocument> dict;
        private const int captchaLenght = 4;

        public Captcha GetCaptcha()
        {
            dict = (Dictionary<string, XDocument>)HttpContext.Current.Application["CaptchaLetters"];

            var resetEvent = new ManualResetEvent(false);
            Exception error = null;

            var thread = new Thread(
                delegate()
                {
                    try
                    {
                        captcha = new Captcha(captchaLenght, dict);
                    }
                    catch (Exception ex)
                    {
                        error = ex;
                    }
                    finally { resetEvent.Set(); }
                });


            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            resetEvent.WaitOne();

            if (error == null && captcha != null)
            {
                HttpContext.Current.Session.Remove("CurrentCaptcha");
                HttpContext.Current.Session.Add("CurrentCaptcha", captcha);

                return captcha;
            }
            else
            {
                throw new Exception("Error in creating captcha", error);
            }
        }        

        #endregion Captcha
        #endregion IGreetingServiceMembers
        #region Methods

        private GreetingResponse ValidateCaptcha(string captchaValidation)
        {
            GreetingResponse response = new GreetingResponse();

            Captcha currentCaptcha = (Captcha)HttpContext.Current.Session["CurrentCaptcha"];
            if(currentCaptcha.Letters.ToLowerInvariant() != captchaValidation.ToLowerInvariant())
            {
                response.Status = GreetingStatus.CaptchaFailed;
                response.Message = "Captcha validation failed, the message has not been saved.";       
            }            

            return response;
        }

        private string SaveGreeting(GreetingData greetingData)
        {
            Greeting greeting = GreetingToGreetingDataTranslator.GreetingDataToGreeting(greetingData);

            using (LinqToGreetingsDBDataContext dataSource = new LinqToGreetingsDBDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["GreetingsDatabaseConnectionString"].ConnectionString))
            {
                dataSource.Greetings.InsertOnSubmit(greeting);
                dataSource.SubmitChanges();
            }

            return greeting.GreetingID.ToString();
        }        

        private GreetingStatus SendGreeting(string id, SenderInfo senderInfo)
        {
            if (senderInfo.RecipientAddresses == null || (senderInfo.RecipientAddresses != null && senderInfo.RecipientAddresses.Count == 0))
            {
                return GreetingStatus.Succeeded;
            }

            // Create the email subject and message.
            StringBuilder emailSubject = new StringBuilder();
            emailSubject.AppendFormat(senderInfo.EmailSubject, senderInfo.Name);

            StringBuilder emailMessage = new StringBuilder();
            emailMessage.AppendFormat(senderInfo.EmailMessage, id);
            emailMessage.AppendLine();

            try
            {
                using (MailMessage mail = new MailMessage())
                {
                    mail.From = new MailAddress(senderInfo.EmailAddress);
                    mail.Subject = emailSubject.ToString();
                    mail.Body = emailMessage.ToString();

                    foreach (string address in senderInfo.RecipientAddresses)
                    {
                        mail.To.Add(new MailAddress(address));
                    }

                    SmtpClient mailClient = new SmtpClient();
                    mailClient.Host = _mailServerName;
                    mailClient.Port = _mailServerPort;
                    mailClient.UseDefaultCredentials = true;
                    mailClient.Send(mail);
                }
            }
            catch (FormatException ex)
            {
                System.Diagnostics.Debug.WriteLine("Failed to send greeting: " + ex);
                return GreetingStatus.SendEmailFailed;
            }
            catch (SmtpException ex)
            {
                System.Diagnostics.Debug.WriteLine("Failed to send greeting: " + ex);
                return GreetingStatus.SendEmailFailed;
            }

            return GreetingStatus.Succeeded;
        }

        #endregion Methods
    }
}
